package com.itydl.a03qq.view;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PointF;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.View;
import android.view.animation.OvershootInterpolator;

import com.itydl.a03qq.GeometryUtil;


/**
 * 作者：${Howard} on 2018/2/6 10:20
 *
 * @version 1.0
 *          说明：仿QQ消息气泡拖拽效果
 */
public class MsgBubbleView extends View {

    private final static String TAG = "MsgBubbleView";

    //固定圆、拖拽圆的坐标对象
    private PointF mFixCircularPoint,mDrgCircularPoint;
    private int mFixRadiusMax = 8;    //固定圆的最大值
    private int mFixRadiusMin = 3;    //固定圆的最小值，防止出现拖拽长了，导致固定圆消失的bug
    private int mFixRadius;           //记录固定圆的半径大小，并绘制该圆
    private int mDragRadius = 10;     //拖拽圆半径大小不变化

    private Paint mPaint;
    private Bitmap mBitmap;           //拖拽真实View（staticView）的bitmap

    public MsgBubbleView(Context context) {
        this(context,null);
    }

    public MsgBubbleView(Context context, AttributeSet attrs) {
        this(context, attrs,0);
    }

    public MsgBubbleView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mFixRadiusMax = dip2px(mFixRadiusMax);
        mFixRadiusMin = dip2px(mFixRadiusMin);
        mDragRadius = dip2px(mDragRadius);
        mPaint = new Paint();
        mPaint.setColor(Color.RED);
        mPaint.setAntiAlias(true);
    }

//    @Override
//    public boolean onTouchEvent(MotionEvent event) {
//        switch (event.getAction()) {
//                case MotionEvent.ACTION_DOWN:
//                    mFixRadius = mFixRadiusMax;//按下的时候，复位固定圆半径就为最大值
//                    float downX = event.getX();
//                    float downY = event.getY();
//                    initDownPoint(downX,downY);
//                    break;
//                case MotionEvent.ACTION_MOVE:
//                    float moveX = event.getX();
//                    float moveY = event.getY();
//                    initDragPoint(moveX,moveY);
//                    break;
//                case MotionEvent.ACTION_UP:
//                    if (mFixRadius >= mFixRadiusMin) {
//                        // 未超过一定距离,松手回弹
//                        resilience();
//                    }else{
//                        // 超过一定距离，松手爆炸
//
//                    }
//                    break;
//         }
//        invalidate();
//        return true;
//    }

    public void handleActionUp(){
        if (mFixRadius >= mFixRadiusMin) {
            // 未超过一定距离,松手回弹
            resilience();
        }else{
            // 超过一定距离，松手爆炸
            if(mMsgBubbleStateListener != null){
                mMsgBubbleStateListener.dismiss(mDrgCircularPoint);
            }
        }
    }

    /**
     * 回弹
     */
    private void resilience() {

        ValueAnimator animator = ValueAnimator.ofFloat(0,1);
        final PointF startPoint = new PointF(mDrgCircularPoint.x, mDrgCircularPoint.y);
        final PointF endPoint = mFixCircularPoint;
        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                float fraction = animation.getAnimatedFraction();//0--->1
                // 根据百分比获取两点之间的某个点坐标。
                PointF pointF = GeometryUtil.getPointByPercent(startPoint,endPoint , fraction);
                updateDragCenter(pointF.x,pointF.y);
            }
        });
        animator.setDuration(350);
        animator.setInterpolator(new OvershootInterpolator(4));
        animator.start();

        animator.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                //回弹动画结束，通知BubbleMesTouchListener的WindowManager移除View，恢复staticView默认状态
                if(mMsgBubbleStateListener != null){
                    mMsgBubbleStateListener.resilience();
                }
            }
        });
    }

    /**
     * 更新拖拽圆圆心坐标, 重绘界面
     * @param x
     * @param y
     */
    private void updateDragCenter(float x, float y) {
        mDrgCircularPoint.set(x, y);
        invalidate();
    }

    /**
     * 初始化拖拽效果的圆的坐标。它随着手指移动在屏幕上移动
     * @param moveX
     * @param moveY
     */
    public void initDragPoint(float moveX, float moveY) {
        mDrgCircularPoint.x = moveX;
        mDrgCircularPoint.y = moveY;
        invalidate();
    }

    /**
     * 初始化按下时候坐标，给固定圆和拖拽圆
     * 按下屏幕的时候，两个圆重叠
     * @param downX
     * @param downY
     */
    public void initDownPoint(float downX, float downY) {
        mFixCircularPoint = new PointF(downX,downY);
        mDrgCircularPoint = new PointF(downX,downY);
        invalidate();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        /**---------  根据坐标，绘制圆形【两个圆，一个固定、一个拖拽】  ---------**/
        if(mDrgCircularPoint == null || mFixCircularPoint == null){
//            Log.e(TAG,"走这里表示为null");
            return;//第一次刚加载View肯定是为null，因为这两个对象在down事件里面初始化的
        }

        //1、绘制拖拽圆，因为大小始终不变化
        canvas.drawCircle(mDrgCircularPoint.x, mDrgCircularPoint.y, mDragRadius, mPaint);

        //2、绘制固定圆，半径随着拖拽距离变小
        Path besselPath = getBesselPath();
        if(besselPath != null){
            canvas.drawCircle(mFixCircularPoint.x,mFixCircularPoint.y,mFixRadius,mPaint);
            //绘制贝塞尔曲线
            canvas.drawPath(besselPath,mPaint);
        }

        if(mBitmap != null){
            //绘制bitmap
            canvas.drawBitmap(mBitmap,mDrgCircularPoint.x-mBitmap.getWidth()/2,mDrgCircularPoint.y-mBitmap.getHeight()/2,null);
        }
    }

    private int dip2px(int dip) {
        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dip, getResources().getDisplayMetrics());
    }

    /**
     * 获取贝塞尔曲线Path对象
     * @return
     */
    public Path getBesselPath() {
        //获取两个圆之间的距离
        double instance = getInstance(mDrgCircularPoint, mFixCircularPoint);
        mFixRadius = (int) (mFixRadiusMax - instance / 15);//随着移动距离的增加，固定圆的半径逐渐变小。为了模拟更好的效果，让长度/14.这个值可以任意定义
        if (mFixRadius < mFixRadiusMin) {
            // 超过一定距离 贝塞尔和固定圆都不要画了[固定圆直接消失掉]
            return null;
        }

        /**---------  绘制贝塞尔曲线  ---------**/
        Path bezeierPath = new Path();

        /**---------  求四个点坐标  ---------**/
        float dy = mDrgCircularPoint.y - mFixCircularPoint.y;
        float dx = mDrgCircularPoint.x - mFixCircularPoint.x;
        double a = Math.atan(dy / dx);

        //p0点
        float p0x = (float) (mFixCircularPoint.x + mFixRadius * Math.sin(a));
        float p0y = (float) (mFixCircularPoint.y - mFixRadius * Math.cos(a));

        //p1点
        float p1x = (float) (mDrgCircularPoint.x + mDragRadius * Math.sin(a));
        float p1y = (float) (mDrgCircularPoint.y - mDragRadius * Math.cos(a));

        //p2点
        float p2x = (float) (mDrgCircularPoint.x - mDragRadius * Math.sin(a));
        float p2y = (float) (mDrgCircularPoint.y + mDragRadius * Math.cos(a));

        //p3点
        float p3x = (float) (mFixCircularPoint.x - mFixRadius * Math.sin(a));
        float p3y = (float) (mFixCircularPoint.y + mFixRadius * Math.cos(a));

        //贝塞尔曲线，控制点。两个圆心的中点坐标
        /**
         * 中点坐标等于两个坐标的平均值
            x=(x1+x2)/2
            y=(y1+y2)/2
         */
        float controlX = (mFixCircularPoint.x + mDrgCircularPoint.x)/2;
        float controlY = (mFixCircularPoint.y + mDrgCircularPoint.y)/2;

        bezeierPath.moveTo(p0x, p0y);
        bezeierPath.quadTo(controlX,controlY,p1x,p1y);
        bezeierPath.lineTo(p2x,p2y);
        bezeierPath.quadTo(controlX,controlY,p3x,p3y);


        return bezeierPath;
    }

    /**
     * 获取两个圆之间的距离
     * @return
     */
    public double getInstance(PointF pointF1,PointF pointF2) {
        return Math.sqrt((pointF1.y - pointF2.y)*(pointF1.y - pointF2.y)
                + (pointF1.x - pointF2.x)*(pointF1.x - pointF2.x));
    }

    /**
     * 绑定任意View
     * @param view
     * @param onBubbleDisappear
     */
    public static void attachView(View view, BubbleMesTouchListener.OnBubbleDisappear onBubbleDisappear) {
        //给任意View设置onTouch监听事件
        view.setOnTouchListener(new BubbleMesTouchListener(view,view.getContext(),onBubbleDisappear));
    }

    public void setBitmap(Bitmap bitmap) {
        mBitmap = bitmap;
    }

    private OnMsgBubbleStateListener mMsgBubbleStateListener;

    public void setOnMsgBubbleStateListener(OnMsgBubbleStateListener onMsgBubbleStateListener){
        this.mMsgBubbleStateListener = onMsgBubbleStateListener;
    }

    public interface OnMsgBubbleStateListener{
        /**
         * 拖拽爆炸结束
         */
        void dismiss(PointF pointF);

        /**
         * 回弹
         */
        void resilience();
    }
}
